package com.yfs.cloud.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import com.yfs.cloud.authority.UserAuthority;
import com.yfs.cloud.authority.UserAuthorityContextHolder;
import com.yfs.cloud.commons.BusinessException;
import com.yfs.cloud.commons.Constants;
import com.yfs.cloud.commons.ResultCode;
import com.yfs.cloud.feign.UserAuthorityFeign;
import com.yfs.cloud.util.JsonUtil;

/**
* @Company: 影法師工作室
* @Description: 鉴权拦截器, 这里鉴的是模块权限, 也就是 URL 的权限
* @author 影法師  
* @date 2020年8月25日 上午10:16:25 
* @version V1.0
 */
@Component
public class AuthInterceptor implements HandlerInterceptor {

	@Autowired
	private UserAuthorityFeign userAuthorityFeign;

	@Value("${com.yfs.cloud.auth.enable}")
	private Boolean authEnable;

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		// 直接从 http 首部获取用户id
		String userIdStr = request.getHeader(Constants.USER_ID);
		// 从 http 首部获取 FEIGN_INNER 首部
		String feignInner = request.getHeader(Constants.FEIGN_INNER);
		// 获取用户角色、权限信息的头
		String userAuthorityJson = request.getHeader(Constants.USER_AUTHORITY_HEADER);
		// 对于不需要jwt认证的接口, 所以userIdStr 是有可能 null 的. 既然 jwt 认证都不需要了, 那么授权自然不需要再继续进行下去了,
		// 所以直接放行, 或者内部的 feign 调用, 比如feign调用用户的/user/findUserAuthority 的接口, 就不需要鉴权了
		if (StringUtils.isBlank(userIdStr) || StringUtils.isNoneBlank(feignInner)) {
			return true;
		}
		// 得到用户 id
		Long userId = Long.parseLong(userIdStr);
		// 如果没开启授权+鉴权, 则仅仅知道用户id就行了, 用户id还是需要知道的. 例如一个情景是, 一个微服务调用用户feign接口的时候要传当前用户id的话, 则UserAuthorityContextHolder中肯定要有userId的
		if (!authEnable) {
			UserAuthority userAuthority = new UserAuthority();
			userAuthority.setUserId(userId);
			UserAuthorityContextHolder.setUserInfo(userAuthority);
			return true;
		}
		// 用户试图访问的接口, 类似于 /lr/register、/user/findUserAuthority/2019 等等, 注意, 此时转发到了微服务,
		// 网关已经将 /api 给 strip 掉了
		String requestURI = request.getRequestURI();
		// 如果没检查到角色、权限头的话, 表明这是第一次进行微服务调用链, 则需要去调用feign接口查询用户的角色、权限信息
		if (StringUtils.isBlank(userAuthorityJson)) {
			// 获取用户角色、模块权限等信息构成的 json 串, 类似于这种
			// {"code":100,"msg":"成功","data":{"userId":1,"roles":["admin"],"modules":["/user","/goods","/order"]}}
			userAuthorityJson = userAuthorityFeign.findUserAuthority(userId);
		}
		// 将feign接口返回的结果转换为 UserAuthority 对象
		UserAuthority userAuthority = JsonUtil.feignResult2Object(userAuthorityJson, UserAuthority.class);
		// 填充用户角色、模块权限等信息
		UserAuthorityContextHolder.setUserInfo(userAuthority);
		// 如果拥有模块权限的话
		for (String module : userAuthority.getModules()) {
			// requestURI 大概是 /user/findUserAuthority/2019 这个样子
			if (requestURI.startsWith(module)) {
				return true;
			}
		}
		// 模块权限(也就是 URL 权限)不足, 被拦截
		throw new BusinessException(ResultCode.ACCESS_DENY);
	}

}
